home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / vg-2.03 / filemenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  8.8 KB  |  448 lines

  1. /*
  2.  * Copyright (C) 1990-1992 by Michael Davidson.
  3.  * All rights reserved.
  4.  *
  5.  * Permission to use, copy, modify, and distribute this software
  6.  * and its documentation for any purpose and without fee is hereby
  7.  * granted, provided that the above copyright notice appear in all
  8.  * copies and that both that copyright notice and this permission
  9.  * notice appear in supporting documentation.
  10.  *
  11.  * This software is provided "as is" without express or implied warranty.
  12.  */
  13.  
  14. /*
  15.  * file selection menu
  16.  */
  17. #include    <stdio.h>
  18.  
  19. #include    "vg.h"
  20. #include    "kbd.h"
  21. #include    "text.h"
  22. #include    "video.h"
  23.  
  24. static int    FileMenuMode        = -1;
  25. static vmode_t    *FileMenuModeInfo    = NULL;
  26.  
  27. extern char    *CurrentDirectory;
  28.  
  29. extern void    *alloca(int);
  30.  
  31. #define    CURSOR        1
  32. #define    SELECTED    2
  33.  
  34. typedef struct row_col
  35. {
  36.     int        row;
  37.     int        col;
  38. } row_col_t;
  39.  
  40.  
  41. void
  42. fileMenu(
  43.     list_t    *filelist
  44.     )
  45. {
  46.     int        x, y, width, height;
  47.     list_t    *f;
  48.     list_t    *l;
  49.     list_t    **ll;
  50.     list_t    ***list_layout;
  51.     unsigned char    *p;
  52.  
  53.     int        nitems;        /* total # of items in list    */
  54.     int        rows;        /* total # of rows in list    */
  55.     int        cols;        /* total # of columns in list    */
  56.     int        row;        /* current row            */
  57.     int        col;        /* current column        */
  58.     int        col_width;    /* width of one column        */
  59.     row_col_t    first;        /* first displayed item in list    */
  60.     row_col_t    last;        /* last item in list        */
  61.     row_col_t    cursor;        /* cursor position in list    */
  62.     row_col_t    info;        /* file info position        */
  63.     int        info_len;    /* file info length        */
  64.     char    *info_buf;
  65.     int        display_rows;    /* # of displayable rows    */
  66.     int        display_cols;    /* # of displayable columns    */
  67.     extern int    nomenu;
  68.     extern int    menuwidth;
  69.  
  70.     if (nomenu)
  71.     {
  72.     for (f = filelist; f != NULL; f = f->next)
  73.         f->flags |= 2;
  74.     showFiles(filelist);
  75.     return;
  76.     }
  77.     if (FileMenuMode == -1)
  78.     {
  79.     FileMenuMode    = bestDisplayMode(V_TEXT_MODE, menuwidth, 25, 0);
  80.     FileMenuModeInfo= vidModeInfo(FileMenuMode);
  81.     }
  82.     vidSetMode(FileMenuMode);
  83.  
  84.     vidClear(BLUE);
  85.  
  86.     menuBorders(0, 0, FileMenuModeInfo->width, FileMenuModeInfo->height,
  87.     CurrentDirectory, "");
  88.  
  89.     info.row    = FileMenuModeInfo->height - 2;
  90.     info.col    = 2;
  91.     info_len    = FileMenuModeInfo->width - 4;
  92.     info_buf    = (char *)alloca(info_len);
  93.  
  94.     /*
  95.      * calculate # of items and maximum length of an item name
  96.      */
  97.     x        = 2;
  98.     y        = 3;
  99.     width    = FileMenuModeInfo->width - 4;
  100.     height    = FileMenuModeInfo->height - 6;
  101.  
  102.     col_width    = 0;
  103.     nitems    = 0;
  104.  
  105.     for (l = filelist; l != NULL; l = l->next)
  106.     {
  107.     int    len;
  108.  
  109.     len    = strlen(l->name);
  110.     if (len > col_width)
  111.         col_width = len;
  112.     ++nitems;
  113.     }
  114.  
  115.     if (nitems == 0)
  116.     return ;
  117.  
  118.     /*
  119.      * calculate # of rows and colums in list
  120.      */
  121.     /*
  122.      * for now just use a fixed formula for this - later
  123.      * should allow this to be specified
  124.      */
  125.     rows    = height;
  126.     cols    = (nitems + (rows - 1)) / rows;
  127.  
  128.     /*
  129.      * build a 2-D array of pointers to the list items indexed
  130.      * by column and row number
  131.      */
  132.     p        = alloca(cols*sizeof(list_t **) + rows*cols*sizeof(list_t *));
  133.             
  134.     /*
  135.      * set up the column pointers
  136.      */
  137.     list_layout    = (list_t ***)p;
  138.     ll        = (list_t **) (p + (cols * sizeof(list_t **)));
  139.     for (col = 0; col < cols; col++)
  140.     {
  141.     list_layout[col] = ll;
  142.     ll += rows;
  143.     }
  144.  
  145.     cursor.row    = 0;
  146.     cursor.col    = 0;
  147.     /*
  148.      * fill in the pointers to the actual list items
  149.      */
  150.     l = filelist;
  151.     for (col = 0; col < cols; col++)
  152.     for (row = 0; row < rows; row++)
  153.     {
  154.         list_layout[col][row] = l;
  155.         if (l != NULL)
  156.         {
  157.         if (l->flags & CURSOR)
  158.         {
  159.             cursor.row = row;
  160.             cursor.col = col;
  161.         }
  162.         l = l->next;
  163.         }
  164.     }
  165.  
  166.     /*
  167.      * calculate # of rows and columns that can be displayed in the window
  168.      */
  169.     display_rows = height;
  170.     display_cols = width / (col_width + 1);
  171.     if (display_cols == 0)
  172.     display_cols = 1;
  173.     col_width = width / display_cols;
  174.     if (display_cols > cols)
  175.     display_cols = cols;
  176.  
  177.     /*
  178.      * first list item to display
  179.      */
  180.     first.row    = 0;
  181.     first.col    = 0;
  182.     last.col    = cols - 1;
  183.     last.row    = nitems - (rows * (cols-1)) - 1;
  184.  
  185.     list_layout[cursor.col][cursor.row]->flags |= CURSOR;
  186.  
  187.      for (;;)
  188.      {
  189.     row_col_t    old_cursor;
  190.     int        cursor_changed;
  191.     int        redraw;
  192.  
  193.     /*
  194.      * redraw the the list
  195.      */
  196.     vidClear(BLUE);
  197.  
  198.     menuBorders(0, 0, FileMenuModeInfo->width, FileMenuModeInfo->height,
  199.         CurrentDirectory, "");
  200.  
  201.     for (col = 0; col < display_cols; col++)
  202.     {
  203.         int        ix;
  204.         int        iy;
  205.         int        iw;
  206.  
  207.         ix    = x + (col * col_width);
  208.         iw    = col_width - 1;
  209.         if (ix + iw > x + width)
  210.         iw = (x + width) - ix;
  211.         for (row = 0, iy = y; row < display_rows;  row++, iy++)
  212.         drawListItem(ix, iy, iw,
  213.             list_layout[first.col + col][first.row + row]);
  214.     }
  215.     /*
  216.      * update file info
  217.      */
  218.     memset(info_buf, ' ', info_len);
  219.     fileInfo(list_layout[cursor.col][cursor.row]->name, info_buf, info_len);
  220.     vidPutText(info.col, info.row, info_buf, info_len, LT_CYAN, BLUE);
  221.  
  222.     redraw    = 0;
  223.  
  224.     while (! redraw)
  225.     {
  226.         int        key;
  227.  
  228.         cursor_changed    = 0;
  229.         old_cursor        = cursor;
  230.  
  231.         key = kbdGetKey(K_WAIT);
  232.  
  233.         switch (key)
  234.         {
  235.         case K_UP:    /* cursor up    */
  236.             --cursor.row;
  237.             cursor_changed = 1;
  238.             break;
  239.  
  240.         case ' ':    /* select    */
  241.             list_layout[cursor.col][cursor.row]->flags ^= SELECTED;
  242.         /* fall through */
  243.         case K_DOWN:    /* cursor down    */
  244.             ++cursor.row;
  245.             cursor_changed = 1;
  246.             break;
  247.  
  248.         case K_RIGHT:        /* cursor right    */
  249.             ++cursor.col;
  250.             cursor_changed = 1;
  251.             break;
  252.  
  253.         case K_LEFT:        /* cursor right    */
  254.             --cursor.col;
  255.             cursor_changed = 1;
  256.             break;
  257.  
  258.         case K_HOME:
  259.             cursor.col    = 0;
  260.             cursor.row    = 0;
  261.             cursor_changed = 1;
  262.             break;
  263.  
  264.         case K_END:
  265.             cursor    = last;
  266.             cursor_changed = 1;
  267.             break;
  268.  
  269.         case K_ENTER:
  270.             for (l = filelist; l != NULL; l = l->next)
  271.             if (l->flags & SELECTED)
  272.                 break;
  273.  
  274.             if (l == NULL)
  275.             list_layout[cursor.col][cursor.row]->flags |= SELECTED;
  276.  
  277.             showFiles(filelist);
  278.  
  279.             for (l = filelist; l != NULL; l = l->next)
  280.             l->flags &= ~SELECTED;
  281.  
  282.             vidSetMode(FileMenuMode);
  283.             ++redraw;
  284.             break;
  285.  
  286.         case K_ESCAPE:
  287.             return;
  288.  
  289.         }    /* end of switch(key)        */
  290.  
  291.         /*
  292.          * update cursor status
  293.          */
  294.          if (cursor_changed)
  295.          {
  296.         /*
  297.          * check row and update column if necessary
  298.          */
  299.         if (cursor.row < 0)
  300.         {
  301.             if (--cursor.col >= 0)
  302.             cursor.row = rows - 1;
  303.             else
  304.             {
  305.             cursor.row = 0;
  306.             cursor.col = 0;
  307.             }
  308.         }
  309.         else if (cursor.row >= rows)
  310.         {
  311.             if (++cursor.col < cols)
  312.             cursor.row    = 0;
  313.             else
  314.             {
  315.             cursor.row = rows - 1;
  316.             cursor.col = cols - 1;
  317.             }
  318.         }
  319.  
  320.         /*
  321.          * check column and range limit
  322.          */
  323.         if (cursor.col < 0)
  324.         {
  325.             cursor.col    = 0;
  326.         }
  327.         else if (cursor.col >= cols)
  328.         {
  329.             cursor.col = cols - 1;
  330.         }
  331.  
  332.         /*
  333.          * check for empty entries in the last column
  334.          */
  335.         if (cursor.col == last.col && cursor.row > last.row)
  336.             cursor = last;
  337.  
  338.         
  339.         /*
  340.          * check whether a complete redraw is necessary
  341.          */
  342.         if (cursor.col < first.col)
  343.         {
  344.             first.col = cursor.col;
  345.             ++redraw;
  346.         }
  347.         else if (cursor.col >= first.col + display_cols)
  348.         {
  349.             first.col    = cursor.col - (display_cols - 1);
  350.             ++redraw;
  351.         }
  352.  
  353.         if (cursor.row < first.row)
  354.         {
  355.             first.row = cursor.row;
  356.             ++redraw;
  357.         }
  358.         else if (cursor.row >= first.row + display_rows)
  359.         {
  360.             first.row    = cursor.row - (display_rows - 1);
  361.             ++redraw;
  362.         }
  363.  
  364.         /*
  365.          * update cursor flags
  366.          */
  367.         list_layout[old_cursor.col][old_cursor.row]->flags &= ~CURSOR;
  368.         list_layout[cursor.col][cursor.row]->flags |= CURSOR;
  369.         /*
  370.          * update old and new cursor positions
  371.          * if redraw is TRUE then everything will get redrawn
  372.          */
  373.         if (! redraw)
  374.         {
  375.             int        iw, ix, iy;
  376.  
  377.             col    = old_cursor.col;
  378.             row    = old_cursor.row;
  379.  
  380.             l = list_layout[col][row];
  381.             ix    = x + (col - first.col) * col_width;
  382.             iy    = y + (row - first.row);
  383.             iw    = col_width - 1;
  384.             if (ix + iw > x + width)
  385.             iw = (x + width) - ix;
  386.  
  387.             drawListItem(ix, iy, iw, l);
  388.  
  389.             col    = cursor.col;
  390.             row    = cursor.row;
  391.  
  392.             l = list_layout[col][row];
  393.             ix    = x + (col - first.col) * col_width;
  394.             iy    = y + (row - first.row);
  395.             iw    = col_width - 1;
  396.             if (ix + iw > x + width)
  397.             iw = (x + width) - ix;
  398.  
  399.             drawListItem(ix, iy, iw, l);
  400.  
  401.             /*
  402.              * update file info
  403.              */
  404.             memset(info_buf, ' ', info_len);
  405.             fileInfo(l->name, info_buf, info_len);
  406.             vidPutText(info.col, info.row, info_buf, info_len,
  407.             LT_CYAN, BLUE);
  408.         }
  409.         }
  410.     }    /* end of while (! redraw)    */
  411.  
  412.     }   /* end of for(;;)    */
  413. }
  414.  
  415. drawListItem(
  416.     int        x,
  417.     int        y,
  418.     int        w,
  419.     list_t    *l
  420.     )
  421. {
  422.     char    buf[256];
  423.     int        fg;
  424.     int        bg;
  425.  
  426.     memset(buf, ' ', w);
  427.     fg    = LT_CYAN;
  428.     bg    = BLUE;
  429.  
  430.     if (l != NULL)
  431.     {
  432.     strcpy(buf, l->name);
  433.  
  434.     if (l->flags & SELECTED)
  435.         fg = LT_GREEN;
  436.  
  437.     if (l->flags & CURSOR)
  438.     {
  439.         int    tmp;
  440.  
  441.         tmp    = fg;
  442.         fg    = bg;
  443.         bg    = tmp;
  444.     }
  445.     }
  446.     vidPutText(x, y, buf, w, fg, bg);
  447. }
  448.